/*******************************************************************************
 * Copyright (c) 2015 Lincong All rights reserved.
 * This software is the confidential and proprietary information of Lincong.
 * You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with Lincong.
 *  Mail: Lincong <lincong1987@gmail.com>, <lincong@cleverlin.com>
 *    QQ: 159257119
 * Phone: 15925711961
 * $Revision$
 * $Id$
 ******************************************************************************/

/*!
 * The Firebird Javascript Lite Lib.
 *
 * http://www.jplatformx.com/
 *
 * editor lc
 * $Id: firebird-1.0.3.js 16 2014-01-23 10:21:08Z lc $
 *
 * based on baidu tangram 1.5.2.2
 * http://tangram.baidu.com
 */
var _define_ = "define(function(require, exports, module) {})";


if (typeof JSON !== 'object') {
	JSON = {};
}

(function () {
	'use strict';

	var rx_one = /^[\],:{}\s]*$/,
		rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
		rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
		rx_four = /(?:^|:|,)(?:\s*\[)+/g,
		rx_escapable = /[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
		rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;

	function f(n) {
		// Format integers to have at least two digits.
		return n < 10
			? '0' + n
			: n;
	}

	function this_value() {
		return this.valueOf();
	}

	if (typeof Date.prototype.toJSON !== 'function') {

		Date.prototype.toJSON = function () {

			return isFinite(this.valueOf())
				? this.getUTCFullYear() + '-' +
				f(this.getUTCMonth() + 1) + '-' +
				f(this.getUTCDate()) + 'T' +
				f(this.getUTCHours()) + ':' +
				f(this.getUTCMinutes()) + ':' +
				f(this.getUTCSeconds()) + 'Z'
				: null;
		};

		Boolean.prototype.toJSON = this_value;
		Number.prototype.toJSON = this_value;
		String.prototype.toJSON = this_value;
	}

	var gap,
		indent,
		meta,
		rep;


	function quote(string) {

// If the string contains no control characters, no quote characters, and no
// backslash characters, then we can safely slap some quotes around it.
// Otherwise we must also replace the offending characters with safe escape
// sequences.

		rx_escapable.lastIndex = 0;
		return rx_escapable.test(string)
			? '"' + string.replace(rx_escapable, function (a) {
			var c = meta[a];
			return typeof c === 'string'
				? c
				: '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
		}) + '"'
			: '"' + string + '"';
	}


	function str(key, holder) {

// Produce a string from holder[key].

		var i,          // The loop counter.
			k,          // The member key.
			v,          // The member value.
			length,
			mind = gap,
			partial,
			value = holder[key];

// If the value has a toJSON method, call it to obtain a replacement value.

		if (value && typeof value === 'object' &&
			typeof value.toJSON === 'function') {
			value = value.toJSON(key);
		}

// If we were called with a replacer function, then call the replacer to
// obtain a replacement value.

		if (typeof rep === 'function') {
			value = rep.call(holder, key, value);
		}

// What happens next depends on the value's type.

		switch (typeof value) {
			case 'string':
				return quote(value);

			case 'number':

// JSON numbers must be finite. Encode non-finite numbers as null.

				return isFinite(value)
					? String(value)
					: 'null';

			case 'boolean':
			case 'null':

// If the value is a boolean or null, convert it to a string. Note:
// typeof null does not produce 'null'. The case is included here in
// the remote chance that this gets fixed someday.

				return String(value);

// If the type is 'object', we might be dealing with an object or an array or
// null.

			case 'object':

// Due to a specification blunder in ECMAScript, typeof null is 'object',
// so watch out for that case.

				if (!value) {
					return 'null';
				}

// Make an array to hold the partial results of stringifying this object value.

				gap += indent;
				partial = [];

// Is the value an array?

				if (Object.prototype.toString.apply(value) === '[object Array]') {

// The value is an array. Stringify every element. Use null as a placeholder
// for non-JSON values.

					length = value.length;
					for (i = 0; i < length; i += 1) {
						partial[i] = str(i, value) || 'null';
					}

// Join all of the elements together, separated with commas, and wrap them in
// brackets.

					v = partial.length === 0
						? '[]'
						: gap
							? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
							: '[' + partial.join(',') + ']';
					gap = mind;
					return v;
				}

// If the replacer is an array, use it to select the members to be stringified.

				if (rep && typeof rep === 'object') {
					length = rep.length;
					for (i = 0; i < length; i += 1) {
						if (typeof rep[i] === 'string') {
							k = rep[i];
							v = str(k, value);
							if (v) {
								partial.push(quote(k) + (
									gap
										? ': '
										: ':'
								) + v);
							}
						}
					}
				} else {

// Otherwise, iterate through all of the keys in the object.

					for (k in value) {
						if (Object.prototype.hasOwnProperty.call(value, k)) {
							v = str(k, value);
							if (v) {
								partial.push(quote(k) + (
									gap
										? ': '
										: ':'
								) + v);
							}
						}
					}
				}

// Join all of the member texts together, separated with commas,
// and wrap them in braces.

				v = partial.length === 0
					? '{}'
					: gap
						? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
						: '{' + partial.join(',') + '}';
				gap = mind;
				return v;
		}
	}

// If the JSON object does not yet have a stringify method, give it one.

	if (typeof JSON.stringify !== 'function') {
		meta = {    // table of character substitutions
			'\b': '\\b',
			'\t': '\\t',
			'\n': '\\n',
			'\f': '\\f',
			'\r': '\\r',
			'"': '\\"',
			'\\': '\\\\'
		};
		JSON.stringify = function (value, replacer, space) {

// The stringify method takes a value and an optional replacer, and an optional
// space parameter, and returns a JSON text. The replacer can be a function
// that can replace values, or an array of strings that will select the keys.
// A default replacer method can be provided. Use of the space parameter can
// produce text that is more easily readable.

			var i;
			gap = '';
			indent = '';

// If the space parameter is a number, make an indent string containing that
// many spaces.

			if (typeof space === 'number') {
				for (i = 0; i < space; i += 1) {
					indent += ' ';
				}

// If the space parameter is a string, it will be used as the indent string.

			} else if (typeof space === 'string') {
				indent = space;
			}

// If there is a replacer, it must be a function or an array.
// Otherwise, throw an error.

			rep = replacer;
			if (replacer && typeof replacer !== 'function' &&
				(typeof replacer !== 'object' ||
					typeof replacer.length !== 'number')) {
				throw new Error('JSON.stringify');
			}

// Make a fake root object containing our value under the key of ''.
// Return the result of stringifying the value.

			return str('', {'': value});
		};
	}


// If the JSON object does not yet have a parse method, give it one.

	if (typeof JSON.parse !== 'function') {
		JSON.parse = function (text, reviver) {

// The parse method takes a text and an optional reviver function, and returns
// a JavaScript value if the text is a valid JSON text.

			var j;

			function walk(holder, key) {

// The walk method is used to recursively walk the resulting structure so
// that modifications can be made.

				var k, v, value = holder[key];
				if (value && typeof value === 'object') {
					for (k in value) {
						if (Object.prototype.hasOwnProperty.call(value, k)) {
							v = walk(value, k);
							if (v !== undefined) {
								value[k] = v;
							} else {
								delete value[k];
							}
						}
					}
				}
				return reviver.call(holder, key, value);
			}


// Parsing happens in four stages. In the first stage, we replace certain
// Unicode characters with escape sequences. JavaScript handles many characters
// incorrectly, either silently deleting them, or treating them as line endings.

			text = String(text);
			rx_dangerous.lastIndex = 0;
			if (rx_dangerous.test(text)) {
				text = text.replace(rx_dangerous, function (a) {
					return '\\u' +
						('0000' + a.charCodeAt(0).toString(16)).slice(-4);
				});
			}


			if (
				rx_one.test(
					text
						.replace(rx_two, '@')
						.replace(rx_three, ']')
						.replace(rx_four, '')
				)
			) {

// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
// in JavaScript: it can begin a block or an object literal. We wrap the text
// in parens to eliminate the ambiguity.

				j = eval('(' + text + ')');

// In the optional fourth stage, we recursively walk the new structure, passing
// each name/value pair to a reviver function for possible transformation.

				return typeof reviver === 'function'
					? walk({'': j}, '')
					: j;
			}

// If the text is not JSON parseable, then a SyntaxError is thrown.

			throw new SyntaxError('JSON.parse');
		};
	}
}());


(function (win, doc) {

	/**
	 * 框架主体
	 * @namespace firebird
	 */
	var FB, firebird = FB = firebird || {
		/**
		 * version
		 */
		version: "1.0.3",
		/**
		 * PERIOD
		 */
		PERIOD: ".",
		/**
		 *  DEBUG < INFO < WARN < ERROR
		 */
		debugLevel: "ALL",
		/**
		 * language
		 */
		language: "zh_CN",
		/**
		 * _startTime
		 */
		_startTime: new Date().getTime(),
		/**
		 * noop
		 * an empty function
		 */
		noop: function () {
		}
	};
	win.console = win.console || {
		log: FB.noop,
		info: FB.noop,
		warn: FB.noop,
		error: FB.noop,
		group: FB.noop,
		groupEnd: FB.noop,
		time: FB.noop,
		timeEnd: FB.noop,
		table: FB.noop
	};

	for (var fn in win.console) {
		firebird[fn] = function () {
			var args = arguments;
			Function.apply.apply(window.console.trace || window.console[fn], [window.console, args]);
		}
	}

	/**
	 * @namespace firebird.json
	 * @type type
	 */
	firebird.json = firebird.json || {};
	/**
	 * 将字符串解析成json对象。注:不会自动祛除空格
	 * @name firebird.json.parse
	 * @function
	 * @grammar firebird.json.parse(data)
	 * @param {string} data 需要解析的字符串
	 * @remark
	 * 该方法的实现与ecma-262第五版中规定的JSON.parse不同,暂时只支持传入一个参数。后续会进行功能丰富。
	 * @meta standard
	 * @see firebird.json.stringify,firebird.json.decode
	 *
	 * @returns {JSON} 解析结果json对象
	 */
	firebird.json.parse = function (data) {
		return (new Function("return (" + data + ")"))();
	};
	/**
	 * 将字符串解析成json对象,为过时接口,今后会被firebird.json.parse代替
	 * @name firebird.json.decode
	 * @function
	 * @deprecated
	 * @grammar firebird.json.decode(source)
	 * @param {string} source 需要解析的字符串
	 * @meta out
	 * @see firebird.json.encode,firebird.json.parse
	 *
	 * @returns {JSON} 解析结果json对象
	 */
	firebird.json.decode = firebird.json.parse;
	/**
	 * 将json对象序列化
	 * @name firebird.json.stringify
	 * @function
	 * @grammar firebird.json.stringify(value)
	 * @remark
	 * 该方法的实现与ecma-262第五版中规定的JSON.stringify不同,暂时只支持传入一个参数。后续会进行功能丰富。
	 * @meta standard
	 * @see firebird.json.parse,firebird.json.encode
	 *
	 * @returns {string} 序列化后的字符串
	 */
	firebird.json.stringify = (function () {
		/**
		 * 字符串处理时需要转义的字符表
		 * @private
		 */
		var escapeMap = {
			"\b": '\\b',
			"\t": '\\t',
			"\n": '\\n',
			"\f": '\\f',
			"\r": '\\r',
			'"': '\\"',
			"\\": '\\\\'
		};

		/**
		 * 字符串序列化
		 * @private
		 * @param {String} source
		 */
		function encodeString(source) {
			if (/["\\\x00-\x1f]/.test(source)) {
				source = source.replace(
					/["\\\x00-\x1f]/g,
					function (match) {
						var c = escapeMap[match];
						if (c) {
							return c;
						}
						c = match.charCodeAt();
						return "\\u00"
							+ Math.floor(c / 16).toString(16)
							+ (c % 16).toString(16);
					});
			}
			return '"' + source + '"';
		}

		/**
		 * 数组序列化
		 * @private
		 * @param {String} source
		 */
		function encodeArray(source) {
			var result = ["["],
				l = source.length,
				preComma, i, item;
			for (i = 0; i < l; i++) {
				item = source[i];
				switch (typeof item) {
					case "undefined":
					case "function":
					case "unknown":
						break;
					default:
						if (preComma) {
							result.push(',');
						}
						result.push(firebird.json.stringify(item));
						preComma = 1;
				}
			}
			result.push("]");
			return result.join("");
		}

		/**
		 * 处理日期序列化时的补零
		 * @private
		 * @param {String} source
		 */
		function pad(source) {
			return source < 10 ? '0' + source : source;
		}

		/**
		 * 日期序列化
		 * @private
		 * @param {String} source
		 */
		function encodeDate(source) {
			return '"' + source.getFullYear() + "-"
				+ pad(source.getMonth() + 1) + "-"
				+ pad(source.getDate()) + "T"
				+ pad(source.getHours()) + ":"
				+ pad(source.getMinutes()) + ":"
				+ pad(source.getSeconds()) + '"';
		}

		return function (value) {
			switch (typeof value) {
				case 'undefined':
					return 'undefined';
				case 'number':
					return isFinite(value) ? String(value) : "null";
				case 'string':
					return encodeString(value);
				case 'boolean':
					return String(value);
				default:
					if (value === null) {
						return 'null';
					} else if (value instanceof Array) {
						return encodeArray(value);
					} else if (value instanceof Date) {
						return encodeDate(value);
					} else {
						var result = ['{'],
							encode = firebird.json.stringify,
							preComma,
							item;
						for (var key in value) {
							if (Object.prototype.hasOwnProperty.call(value, key)) {
								item = value[key];
								switch (typeof item) {
									case 'undefined':
									case 'unknown':
									case 'function':
										break;
									default:
										if (preComma) {
											result.push(',');
										}
										preComma = 1;
										result.push(encode(key) + ':' + encode(item));
								}
							}
						}
						result.push('}');
						return result.join('');
					}
			}
		};
	})();
	/**
	 * 将json对象序列化,为过时接口,今后会被firebird.json.stringify代替
	 * @name firebird.json.encode
	 * @function
	 * @grammar firebird.json.encode(value)
	 * @param {JSON} value 需要序列化的json对象
	 * @meta out
	 * @see firebird.json.decode,firebird.json.stringify
	 *
	 * @returns {string} 序列化后的字符串
	 */
	firebird.json.encode = firebird.json.stringify;
	/**
	 * 提供数据缓存功能
	 * @namespace firebird.data
	 */
	firebird.data = firebird.data || {};

	firebird.data.getTop = function () {
		if (this.top) {
			return this.top;
		}
		this.top = window;
		try {
			this.top = window.top;
		} catch (e) {

		}
		return this.top;
	};

	/**
	 * 跨框架数据共享接口
	 * @param {String} key 存储的数据名
	 * @param {Everything} value 将要存储的任意数据
	 * @param {String} area 存储区域 如果key起始为firebird_或top.开头将存入$FIREBIRD_SYS$
	 * @return {Everything} 返回被存储的数据
	 * @example firebird.data.set("dsw", {id:"dsw", name: "daishaowei", sex: "male"});
	 */
	firebird.data.set = function (key, value, area, trigger) {
		var top = this.getTop(),
			area = area || '$FIREBIRD_CACHE$',
			area = key.toString().match(/^firebird\.|^top\./) ? "$FIREBIRD_SYS$" : area,
			cache = top[area] || {};
		top[area] = cache;

		if (trigger) {
			cache["trigger." + key] = trigger;
		}

		return cache[key] = value;
	};
	/**
	 * 跨框架数据共享接口
	 * @param key 存储的数据名
	 * @param area
	 * @param trigger
	 * @returns {*} 返回被查询的数据
	 * @example firebird.data.get("dsw");
	 */
	firebird.data.get = function (key, area) {
		var top = this.getTop(),
			area = area || '$FIREBIRD_CACHE$',
			area = key.toString().match(/^firebird\.|^top\./) ? "$FIREBIRD_SYS$" : area,
			cache = top[area] || {};
		top[area] = cache;

		var trigger = cache["trigger." + key];
		trigger && trigger();

		return cache[key];
	};

	/**
	 * 数据共享删除接口
	 * @param {String} key 删除的数据名
	 * @example firebird.data.remove("dsw");
	 */
	firebird.data.remove = function (key, area) {
		var area = area || '$FIREBIRD_CACHE$',
			area = key.toString().match(/^firebird\.|^top\./) ? "$FIREBIRD_SYS$" : area,
			cache = this.getTop()[area];
		if (cache && cache[key])
			delete cache[key];
	};
	/**
	 * 数据共享清除接口
	 *
	 * @example
	 * step1:
	 * firebird.data.set("key1", "value1");
	 * firebird.data.set("key2", "value2");
	 * firebird.log("key1 is d%, key2 is d%", firebird.data.set("key1"), firebird.data.set("key2"));
	 * step2:
	 * firebird.data.clear();
	 * firebird.log(firebird.log("key1 is d%, key2 is d%", firebird.data.set("key1"), firebird.data.set("key2")););
	 */
	firebird.data.clear = function (area) {
		var area = area || '$FIREBIRD_CACHE$',
			area = area.toString().match(/^firebird\.|^top\./) ? "$FIREBIRD_SYS$" : area;
		this.getTop()[area] = {};
	};

	firebird.data.clearByPrefix = function (prefix, area) {
		var area = area || '$FIREBIRD_CACHE$',
			area = area.toString().match(/^firebird\.|^top\./) ? "$FIREBIRD_SYS$" : area;

		for (var key in this.getAll(area)) {
			if (key.indexOf(prefix) != -1 || prefix.test(key) == true) {
				firebird.data.remove(key, area);
			}
		}
	};

	/**
	 * 跨框架数据共享接口
	 * @return {Object} 返回被查询的数据
	 * @example firebird.data.getAll();
	 */
	firebird.data.getAll = function (area) {
		var top = this.getTop(),
			area = area || '$FIREBIRD_CACHE$',
			cache = top[area] || {};
		top[area] = cache;
		return cache;
	};


	/**
	 *
	 * @type {firebird.lsdata|*|{}}
	 */
	firebird.lsdata = firebird.lsdata || {};
	/**
	 * 跨框架数据共享接口
	 * @param {String} key 存储的数据名
	 * @param {Everything} value 将要存储的任意数据
	 * @return {Everything} 返回被存储的数据
	 * @example firebird.data.set("dsw", {id:"dsw", name: "daishaowei", sex: "male"});
	 */
	firebird.lsdata.set = function (key, value) {
		this.remove(key);
		localStorage.setItem(key, firebird.json.stringify(value));
		return value;
	};
	/**
	 * 跨框架数据共享接口
	 * @param {String} key 存储的数据名
	 * @return {Everything} 返回被查询的数据
	 * @example firebird.data.get("dsw");
	 */
	firebird.lsdata.get = function (key) {
		var value = localStorage.getItem(key);
		return firebird.json.parse(value);
	};
	/**
	 * 数据共享删除接口
	 * @param {String} key 删除的数据名
	 * @example firebird.data.remove("dsw");
	 */
	firebird.lsdata.remove = function (key) {
		localStorage.removeItem(key);
	};

	/**
	 * 应用通信
	 * @namespace firebird.api
	 * @type type
	 */
	firebird.api = firebird.api || {
		proxy: ""
	};
	/**
	 * 获取应用对象
	 * @param {type} message
	 * @returns {undefined}
	 */
	firebird.api.getApp = function (message) {

	};
	/**
	 * 获取应用窗口
	 * @param {type} message
	 * @returns {undefined}
	 */
	firebird.api.getAppWindow = function (message) {

	};
	/**
	 * 在平台中获取来自app的消息
	 * @param {type} message
	 * @returns {unresolved}
	 */
	firebird.api.message = function (message) {

		if (firebird.api.proxy === "") {
			firebird.log("firebird.api.proxy is undefined");
			return;
		}

		firebird.api.send("message", {
			message: message
		});
	};
	/**
	 * 在平台中打开来自app的弹出申请窗口
	 * @param {type} options
	 * @returns {unresolved}
	 */
	firebird.api.dialog = function (options) {

		if (firebird.api.proxy === "") {
			firebird.log("firebird.api.proxy is undefined");
			return;
		}

		firebird.api.send("dialog", options);
	};
	/**
	 * 跨域发送数据
	 * 数据总长度不能操过2000(ie)
	 * @param {String} type api回调类型
	 * @param {Any} options 任意数据,方法
	 * @returns {unresolved}
	 */
	firebird.api.send = function (type, options) {

		var id = "proxy_" + new Date().getTime();
		var obj = {
			proxy: id,
			type: type,
			data: options
		};
		var hash = encodeURIComponent(firebird.json.stringify(obj));
		var src = firebird.api.proxy + "#" + hash;
		if (firebird.ie && src.length > 2000) {
			firebird.log("firebird.api.proxy: Message Body Is Too Large.");
			return;
		}

		if (this.iframe) {
			this.iframe.src = src;
		} else {
			this.iframe = document.createElement("iframe");
			this.iframe.src = src;
			this.iframe.name = this.iframe.id = obj.proxy;
			this.iframe.style.display = "none";
			document.body.appendChild(this.iframe);
		}

		firebird.log("proxy>>> ", firebird.api.proxy + "#" + hash);
	};


	firebird.api.send2 = function (target, options) {
		new PackProxy(target, options);
	};


	function PackProxy(type, options, startCallback, endCallback) {

		var me = this;

		me.uuid = "proxy_" + new Date().getTime();
		me.type = type;
		me.options = options;
		me.hash = encodeURIComponent(firebird.json.stringify(options));

		me.packageList = [];
		me.buildPackage();

		startCallback && startCallback.apply(me);

		me.getIframe(function () {

			var timer = 0;
			var index = 0;
			var send = function () {
				timer = setTimeout(function () {

					var package = me.packageList[index];
					console.log("doSend Package " + index + ":", package);
					me.doSend(firebird.api.proxy + "#" + encodeURIComponent(firebird.json.stringify(package)));

					if (package.end === true) {
						clearTimeout(timer);
						setTimeout(function () {
							document.body.removeChild(me.iframe);
							me = null;
						}, 1000 * 5);
						endCallback && endCallback.apply(me);
					} else {
						index++;
						send();
					}
				}, 500);
			};

			send();


		});


	}


	PackProxy.prototype.buildPackage = function () {
		var me = this;
		var size = 1500;
		var packageSize = Math.ceil(me.hash.length / size);

		for (var page = 0; page <= packageSize - 1; page++) {
			me.packageList.push({
				type: me.type,
				end: page === (packageSize - 1),
				packageId: me.uuid,
				page: page,
				hash: me.hash.substring((page) * size, (page + 1) * size)
			});
		}
	};

	PackProxy.prototype.getIframe = function (callback) {
		var me = this;
		me.iframe = document.createElement("iframe");
		me.iframe.name = this.iframe.id = this.uuid;
		me.iframe.onload = function () {
			console.log("iframe onload", firebird.api.proxy);
			callback.apply(me);
		};
		this.iframe.src = firebird.api.proxy;
		//this.iframe.style.display = "none";
		document.body.appendChild(this.iframe);
	};

	PackProxy.prototype.doSend = function (src) {
		console.log("doSend:", src);
		this.iframe.src = src;
	};


	firebird.api.send3 = function (type, options) {
		firebird.log("firebird.api.send2 called");

		var id = "proxy_" + new Date().getTime();
		var obj = {
			proxy: id,
			type: type,
			data: options
		};
		var hash = encodeURIComponent(firebird.json.stringify(obj));
		var src = firebird.api.proxy + "#" + hash;
		if (!firebird.ie && src.length > 1500) {
			firebird.log("firebird.api.proxy: Message Body Is Too Large. Try Task Array!");

			var dataHash = encodeURIComponent(firebird.json.stringify(options));
			var size = 1500;
			var page = 0;
			var pageSize = Math.ceil(dataHash.length / size);
			var packId = id;


			var packArray = [];

			for (var i = 0; i <= pageSize - 1; i++) {
				packArray.push({
					type: type,
					end: i === pageSize,
					packId: id,
					page: i,
					hash: dataHash.substring((i) * size, (i + 1) * size)
				});
			}


			firebird.info("Create PackArray:", packArray);

			// hash = encodeURIComponent(firebird.json.stringify(obj));
			// src = firebird.api.proxy + "#" + hash;

			var timer = 0;
			var index = 0;
			var doSend = function () {
				timer = setTimeout(function () {

					if (index === 49) {
						debugger
					}

					var pack = packArray[index];
					firebird.info("doSend Pack:", pack);
					firebird.api.doSend(firebird.api.proxy + "#" + encodeURIComponent(firebird.json.stringify(pack)), pack);

					if (pack.end === true) {
						clearTimeout(timer);
					} else {
						index++;
						doSend();
					}
				}, 500);
			};

			doSend();

		} else {
			firebird.api.doSend(src, obj, hash);
		}


	};

	firebird.api.doSend = function (src, obj, hash) {
		if (this.iframe) {
			this.iframe.src = src;
		} else {
			this.iframe = document.createElement("iframe");
			this.iframe.src = src;
			this.iframe.name = this.iframe.id = obj.proxy;
			//this.iframe.style.display = "none";
			document.body.appendChild(this.iframe);
		}

		//firebird.log("proxy>>> ", firebird.api.proxy + "#" + hash);
	};


	/**
	 *
	 * @param api
	 * @returns {*|Everything}
	 */
	firebird.api.get = function (api) {
		return firebird.data.get(api);
	};

	/**
	 *
	 * @type {set|Function}
	 */
	firebird.api.set = firebird.data.set;
	/**
	 *
	 * @type {Function|*|firebird.data.mix|mix}
	 */
	firebird.api.mix = firebird.data.mix;

	firebird.info("Thanks for using firebird.proxy-" + firebird.version + " javascript library! <lincong1987#gmail.com>");

	/**
	 * 结束
	 */
	firebird.loaded = true;
	window.firebird = firebird;

})(window, document);
